﻿using Microsoft.CodeAnalysis;
using SimpleBoard.Binary;
using SimpleBoard.Project.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Runtime;
using System.ComponentModel;
using SimpleBoard.Project.Binding;

namespace SimpleBoard.Compiler.SourceCodeGenerator
{
    internal class PageSourceGenerator : ISourceCodeGenerator
    {
        private readonly PageInfo pageInfo;
        private readonly IEnumerable<DataBinding> bindings;

        public PageSourceGenerator(PageInfo pageInfo, IEnumerable<DataBinding> dataBindings)
        {
            this.pageInfo = pageInfo;
            this.bindings = dataBindings;
        }

        /// <summary>
        /// 获取依赖的程序集位置
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetAssemblies()
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            var assemblyList = new HashSet<string>
            {
                // System
                typeof(object).Assembly.Location,
                // System.Windows
                typeof(Size).Assembly.Location,
                // System.Windows.Controls
                typeof(Grid).Assembly.Location,
                // System.Windows.Media
                typeof(Color).Assembly.Location,
                // SimpleBoard.Binary
                typeof(IPageGenerator).Assembly.Location,
                // System.ComponentModel
                typeof(TypeConverter).Assembly.Location,
            };
            foreach (var control in pageInfo.Controls)
            {
                var assembly = assemblies.Where(x=>x.FullName == control.AssemblyFullName).Single();
                assemblyList.Add(assembly.Location);
            }
            return assemblyList;
        }

        /// <summary>
        /// 生成源代码
        /// </summary>
        /// <returns></returns>
        public string GenerateSourceCode()
        {
            var code =
@$"
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SimpleBoard.Binary.UI
{{
    internal class PageGenerator : IPageGenerator
    {{
        public Size GetWindowSize() => new ({pageInfo.Width}, {pageInfo.Height});

        public void InitializeComponents(Panel root)
        {{
            // 设置背景颜色
            root.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(""{pageInfo.BackgroundColor}""));
{string.Join(Environment.NewLine, GenerateControlCode(pageInfo.Controls))}
        }}
    }}
}}
";
            return code;
        }

        /// <summary>
        /// 生成控件代码
        /// </summary>
        /// <param name="controls"></param>
        /// <returns></returns>
        private IEnumerable<string> GenerateControlCode(IEnumerable<ControlInfo> controls)
        {
            var it = controls.GetEnumerator();
            var index = 0;
            while (it.MoveNext())
            {
                var control = it.Current;
                var code = 
$@"
            var {control.Name} = new {control.TypeFullName}()
            {{
                Width = {control.Width},
                Height = {control.Height},
                Margin = new Thickness({control.Left}, {control.Top}, 0, 0),
{GeneratePropsCode(control.Properties)}
            }};
{GenerateBindingsCode(control)}
            root.Children.Add(control{index});
            
";
                index++;
                yield return code;
            }
        }

        /// <summary>
        /// 生成属性代码
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        private string GeneratePropsCode(Dictionary<string, object> properties)
        {
            var sb = new StringBuilder();
            foreach (var propertyInfo in properties)
            {
                if(propertyInfo.Value is string)
                    sb.Append(
$@"
                {propertyInfo.Key} = ""{propertyInfo.Value}"",
");
                else
                    sb.Append(
$@"
                {propertyInfo.Key} = {propertyInfo.Value},
");
            }
            return sb.ToString();
        }

        private string GenerateBindingsCode(ControlInfo control)
        {
            var relatedBindings = this.bindings.Where(x => x.ControlName == control.Name);
            var sb = new StringBuilder();
            foreach (var binding in relatedBindings)
            {
                sb.Append(@$"
            BindableProperty.Register(""{binding.DataUnitName}"", {control.Name}, ""{binding.PropertyName}"");
");
            }

            return sb.ToString();
        }
    }
}
